#!/bin/bash

# -eq 等于
# -ne 不等于
# -gt 大于
# -lt 小于
# -ge 大于等于
# -le 小于等于

# 脚本所在目录
# SCRIPT_DIR=$(cd $(dirname $0) && pwd)
# SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
# SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)



get_compiler_type() {
    local compiler_basename
    compiler_basename=$(basename "$1" | tr '[:upper:]' '[:lower:]')

    case "$compiler_basename" in
        gcc | gcc.exe)
            echo "gcc"
            ;;
        g++ | g++.exe)
            echo "g++"
            ;;
        clang | clang.exe)
            echo "clang"
            ;;
        clang++ | clang++.exe)
            echo "clang++"
            ;;
        cl | cl.exe | vcvarsall.bat)
            echo "msvc"
            ;;
        *)
            echo "unknown"  # 未知编译器
            ;;
    esac
}

get_project_name_simple() {
    # 首先尝试直接获取 project() 中的名称
    local project_name=$(grep -oP 'project\s*\(\s*\K[^ )]+' CMakeLists.txt | head -n 1)

    # 如果是 ${VAR} 格式，提取变量名并获取其值
    if [[ "$project_name" =~ ^\$\{([^}]+)\}$ ]]; then
        local var_name=${BASH_REMATCH[1]}
        # 查找 set(var_name "value") 的值
        local var_value=$(grep -oP "set\s*\(\s*${var_name}\s+\"\K[^\"]+" CMakeLists.txt | head -n 1)
        echo "$var_value"
    else
        # 如果是直接赋值的字符串，直接返回
        echo "$project_name"
    fi
}

# !!!注意::
# 切换到脚本所在目录赋值给 SCRIPT_DIR 变量
# 但实际shell中并没有进入脚本所在目录，所以此处的脚本目录是相对路径
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" &> /dev/null && pwd)
if [[ "$OSTYPE" == "cygwin"|| $SCRIPT_DIR == /cygdrive/* ]]; then
    SCRIPT_DIR=$(cygpath -w "$SCRIPT_DIR")
    SCRIPT_DIR=${SCRIPT_DIR//\\//}
fi

CONFIG_FILE="${SCRIPT_DIR}/cb.conf"
if [ ! -f "$CONFIG_FILE" ]; then
    echo "Error: Config file not found: $CONFIG_FILE"
    exit 1
fi
source ${CONFIG_FILE}  # 导入 cb.conf 中的变量

# ${变量名//匹配模式/替换内容}
# C_COMPILER_EXEC="${c_compiler//\\//}"
# CXX_COMPILER_EXEC="${cpp_compiler//\\//}"
[ -n "$c_compiler" ] && C_COMPILER_EXEC="${c_compiler//\\//}"
[ -n "$cpp_compiler" ] && CXX_COMPILER_EXEC="${cpp_compiler//\\//}"
# if [[ "$OSTYPE" == "cygwin"|| $SCRIPT_DIR == /cygdrive/* ]]; then
case "$SCRIPT_DIR" in
  /cygdrive/*)
    is_cygwin_path=true
    ;;
  *)
    is_cygwin_path=false
    ;;
esac
if [ "$OSTYPE" = "cygwin" ] && [ "$is_cygwin_path" = true ]; then
    C_COMPILER_EXEC=$(cygpath -w "$C_COMPILER_EXEC")
    CXX_COMPILER_EXEC=$(cygpath -w "$CXX_COMPILER_EXEC")
    C_COMPILER_EXEC=${C_COMPILER_EXEC//\\//}
    CXX_COMPILER_EXEC=${CXX_COMPILER_EXEC//\\//}
fi

COMPILER_TYPE=""
HOST_ARCH=""
MSVC_ENV_SCRIPT="${msvc_env_script}"

# 如果三个变量都为空或都未找到，则退出
if [ -z "$C_COMPILER_EXEC" ] && [ -z "$CXX_COMPILER_EXEC" ] && [ -z "$MSVC_ENV_SCRIPT" ]; then
    COMPILER_TYPE=""

elif [[ -n "$C_COMPILER_EXEC" && -n "$CXX_COMPILER_EXEC" ]]; then
    if ! command -v "$C_COMPILER_EXEC" >/dev/null 2>&1; then
        echo "C compiler not found."
        exit 1
    fi
    if ! command -v "$CXX_COMPILER_EXEC" >/dev/null 2>&1; then
        echo "C compiler not found."
        exit 1
    fi
    COMPILER_EXEC_P+=(-DCMAKE_C_COMPILER="$C_COMPILER_EXEC" -DCMAKE_CXX_COMPILER="$CXX_COMPILER_EXEC")
    COMPILER_TYPE=$(get_compiler_type "$CXX_COMPILER_EXEC")

elif [[ -n "$C_COMPILER_EXEC" && -z "$CXX_COMPILER_EXEC" ]]; then
    if ! command -v "$C_COMPILER_EXEC" >/dev/null 2>&1; then
        echo "C compiler not found."
        exit 1
    fi
    COMPILER_EXEC_P+=(-DCMAKE_C_COMPILER="$C_COMPILER_EXEC")
    COMPILER_TYPE=$(get_compiler_type "$C_COMPILER_EXEC")

elif [[ -z "$C_COMPILER_EXEC" && -n "$CXX_COMPILER_EXEC" ]]; then
    if ! command -v "$CXX_COMPILER_EXEC" >/dev/null 2>&1; then
        echo "C compiler not found."
        exit 1
    fi
    COMPILER_EXEC_P+=(-DCMAKE_CXX_COMPILER="$CXX_COMPILER_EXEC")
    COMPILER_TYPE=$(get_compiler_type "$CXX_COMPILER_EXEC")

elif [[ -f "$MSVC_ENV_SCRIPT" ]]; then
    if [[ -z "$host_arch" ]]; then
        HOST_ARCH="x64"
    elif [[ -n "$host_arch" ]]; then
        HOST_ARCH="$host_arch"
    fi

    # if [[ "$OSTYPE" == "cygwin" && $is_cygwin_path == true ]]; then
    #     VCToolsInstallDir=$(
    #         cmd.exe /c "call "${MSVC_ENV_SCRIPT}" \
    #         ${HOST_ARCH} >nul && set VCToolsInstallDir" | sed -E 's/^VCToolsInstallDir=//' | tr -d '\r'
    #     )
    # elif [[ ( "$OSTYPE" == "msys" || "$OSTYPE" == "cygwin" ) && "$is_cygwin_path" == false ]]; then
    #     VCToolsInstallDir=$(
    #         cmd.exe //c "call "${MSVC_ENV_SCRIPT}" \
    #         ${HOST_ARCH} >nul && set VCToolsInstallDir" | sed -E 's/^VCToolsInstallDir=//' | tr -d '\r'
    #     )
    # fi
    # [ -n "$VCToolsInstallDir" ] && {
    #     VCToolsInstallDir="${VCToolsInstallDir//\\//}"
    # } || {
    #     echo "Error: MSVC environment script not found."
    #     exit 1
    # }
    # echo "VCToolsInstallDir in bash is: $VCToolsInstallDir"
    # CXX_COMPILER_EXEC=${VCToolsInstallDir}bin/Host${HOST_ARCH}/${HOST_ARCH}/cl.exe
    # echo "CXX_COMPILER_EXEC in bash is: $CXX_COMPILER_EXEC"
    # COMPILER_EXEC_P+=(-DCMAKE_CXX_COMPILER="$CXX_COMPILER_EXEC")
    COMPILER_TYPE=$(get_compiler_type "$MSVC_ENV_SCRIPT")

fi


# echo "Compiler type: $COMPILER_TYPE"
case "$COMPILER_TYPE" in
    "")
        full_version="Default"
        ;;
    "gcc")
        # 获取完整的版本信息
        full_version=$("$C_COMPILER_EXEC" --version | head -n1)
        ;;
    "g++")
        full_version=$("$CXX_COMPILER_EXEC" --version | head -n1)
        ;;
    "clang")
        full_version=$("$C_COMPILER_EXEC" --version | head -n1)
        ;;
    "clang++")
        full_version=$("$CXX_COMPILER_EXEC" --version | head -n1)
        ;;
    "msvc")
        full_version="msvc"
        ;;
    *)
        echo "Error: Unknown compiler type: $COMPILER_TYPE"
        exit 1
        ;;
esac


# echo "Full version info: $full_version"
if [[ "$full_version" == "Default" ]]; then
    compiler_info=""

elif [[ "$full_version" == *"MinGW"* ]]; then
    # MinGW发行版
    version=$(echo "$full_version" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)
    compiler_info="MinGW-$version"

elif [[ "$full_version" == *"g++"* || "$full_version" == *"gcc"* ]]; then
    # GNU GCC发行版
    version=$(echo "$full_version" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)
    compiler_info="GCC-$version"

elif [[ "$full_version" == *"clang"* ]]; then
    # LLVM Clang发行版
    version=$(echo "$full_version" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1)
    compiler_info="Clang-$version"

elif [[ "$full_version" == *"msvc" || "$full_version" == *"Visual Studio"* || "$full_version" == *"Microsoft (R)"* ]]; then
    # MSVC发行版
    compiler_info="MSVC"

else
    # 其他未知编译器
    echo "No valid C and C++ compiler. Exiting."
    exit 1

fi


# 构造编译器信息字符串
if [[ -z "$HOST_ARCH" ]]; then
    COMPILER_INFO="${compiler_info}"
elif [[ -n "$HOST_ARCH" && -n "$compiler_info" ]]; then
    COMPILER_INFO="${compiler_info}-${HOST_ARCH}"
fi

# 默认配置
BUILD_TYPE="${build_type}"
BUILD_TARGET="all"
SOURCE_DIR="${source_dir}"
# BUILD_DIR="${build_dir}"
GENERATOR="${generator}"
PARALLEL_JOBS="${parallel_jobs}"
CONAN_HOST="${conan_host:-default}"
CONAN_BUILD="${conan_build:-default}"


# RUN_ARGS=""
SHOULD_CONFIGURE=false
SHOULD_BUILD=false
SHOULD_RUN=false
SHOULD_CLEAN=false
# SHOULD_RESET=false

# 显示帮助信息
show_help() {
    echo "Usage: ./cb.sh [OPTIONS]"
    echo "C/C++ Build Manager (CMake + gcc/clang/msvc)"
    echo ""
    echo "Options:"
    echo "  Set the compiler type to use."
    # echo "      -s, --set <compiler>            Set the compiler type to use (gcc/g++/clang/clang++/msvc, default: gcc/g++)."
    echo "  Set the default build type to use."
    echo "      -t, --type <build_type>         Set the default build type to use (Debug/Release, default: Debug)."
    echo "  Configure the project."
    echo "      -g, --generate <build_type>       The default way to configure the project. (Debug/Release, default: Debug)."
    echo "  Build the project."
    echo "      -b, --build <build_type>        Build the project. (Debug/Release, default: Debug)."
    echo "          --target=<target>           Build a specific target. (Debug/Release, default: Debug)."
    echo "  Run the executable."
    echo "      -r, --run <build_type>          Run the executable. (Debug/Release, default: Debug)."
    echo "  Clean the build directory."
    echo "      -c, --clean <build_type>        Clean the build directory. (Debug/Release, default: Debug)."
    # echo "  Reset the CMake cache and reconfigure the project."
    # echo "      -R, --reset <build_type>        Reset the CMake cache and reconfigure the project. (Debug/Release, default: Debug)."
    # echo "      -rb --rebuild                   Clean the build directory and rebuild the project."
    echo "  -h, --help                          Show this help message"
    exit 0
}


# 解析命令行参数
while [[ $# -gt 0 ]]; do
    case $1 in
        # -s|--set)
        #     if [[ $# -ne 2 && $3 != -* ]]; then  # 检查参数总数是否为2 并且 $3 不以 - 开头（--set + 编译器名）
        #         echo "\$3: $3"
        #         echo "Error: --set requires exactly (compiler name)"
        #         exit 1
        #     fi

        #     input_compiler=$(echo "$2")
        #     # echo "Setting the compiler to '$2'"
        #     # exit 1

        #     # sed               流编辑器，用于文本查找替换
        #     # -i                直接修改文件（原地替换）
        #     # s/.../.../        替换操作（语法：s/旧模式/新模式/）
        #     # ^compiler=".*"    匹配以 compiler=" 开头，后跟任意字符（.*），直到 " 结束的行
        #     # compiler="gcc"    替换为固定值 compiler="gcc"
        #     # cb.conf       要操作的目标文件
        #     if grep -q '^compiler=' ${CONFIG_FILE}; then
        #         sed -i 's/^compiler=".*"/compiler="'${input_compiler}'"/' ${SCRIPT_DIR}/cb.conf
        #         echo "Compiler type set to '${input_compiler}'"
        #     fi

        #     shift 2  # 跳过 --set 和编译器名
        #     # exit 0
        #     ;;

        -t|--type)
            if [[ $# -eq 1 ]]; then  # 检查参数总数为1（--type）
                current_build_type=$(echo "${build_type}" | tr '[:upper:]' '[:lower:]')
                if [[ $current_build_type == "debug" ]]; then
                    current_build_type="Release"
                elif [[ $current_build_type == "release" ]]; then
                    current_build_type="Debug"
                fi

                if grep -q '^build_type=' ${CONFIG_FILE}; then
                    sed -i 's/^build_type=".*"/build_type="'${current_build_type}'"/' ${SCRIPT_DIR}/cb.conf
                    echo "Build type set to '${current_build_type}'"
                fi
                break;
            fi

            if [[ $# -ne 2 && $3 != -* ]]; then  # 检查参数总数不为2 并且 $3 不以 - 开头（--type + 构建类型）
                echo "Error: -t or --type parameter (-t | -t <build_type>)"
                exit 1
            fi

            input_build_type=$(echo "$2" | tr '[:upper:]' '[:lower:]')
            valid_build_types_lower=()
            for type in "${VALID_BUILD_TYPES[@]}"; do
                valid_build_types_lower+=( "$(echo "$type" | tr '[:upper:]' '[:lower:]')" )
            done

            if [[ ! " ${valid_build_types_lower[*]} " =~ " ${input_build_type} " ]]; then
                echo "error: invalid build type: '${input_build_type}'"
                exit 1
            fi
            if [[ $input_build_type == "debug" ]]; then
                input_build_type="Debug"
            elif [[ $input_build_type == "release" ]]; then
                input_build_type="Release"
            fi

            if grep -q '^build_type=' ${CONFIG_FILE}; then
                sed -i 's/^build_type=".*"/build_type="'${input_build_type}'"/' ${SCRIPT_DIR}/cb.conf
                echo "Build type set to '${input_build_type}'"
            fi

            shift 2  # 跳过 --type 和构建类型
            # exit 0
            ;;

        -g|--generate)
            if [[ $# -eq 1 ]]; then  # 检查参数总数为1（--generate
                SHOULD_CONFIGURE=true
                shift 1  # 跳过 --generate
                break;
            elif [[ $# -ne 2 ]]; then  # 检查参数总数是否为2（--generate + 构建类型）
                echo "Error: -g or --generate parameter (-g | -g <build_type>)"
                exit 1
            fi

            input_build_type=$(echo "$2" | tr '[:upper:]' '[:lower:]')
            # 将有效构建类型数组也转换为小写（避免大小写敏感问题）
            valid_build_types_lower=()
            for type in "${VALID_BUILD_TYPES[@]}"; do
                valid_build_types_lower+=( "$(echo "$type" | tr '[:upper:]' '[:lower:]')" )
            done

            if [[ ! " ${valid_build_types_lower[*]} " =~ " ${input_build_type} " ]]; then
                echo "error: invalid build type: '$2'"
                exit 1
            fi
            if [[ $input_build_type == "debug" ]]; then
                input_build_type="Debug"
            elif [[ $input_build_type == "release" ]]; then
                input_build_type="Release"
            fi

            BUILD_TYPE="${input_build_type}"

            SHOULD_CONFIGURE=true

            shift 2  # 跳过 --config 和构建类型
            # exit 0
            ;;

        -b|--build)
            case $# in
                1)  # 只有 -b/--build
                    SHOULD_BUILD=true
                    shift 1  # 跳过 -b/--build
                    break;
                    ;;
                2)  # -b/--build <type>
                    if [[ $2 == "--target" ]]; then
                        echo "Error: -b or --build parameter (-b | -b <build_type> | -b --target <target> | -b <build_type> --target <target>)"
                        exit 1
                    fi
                    
                    input_build_type=$(echo "$2" | tr '[:upper:]' '[:lower:]')
                    valid_build_types_lower=()
                    for type in "${VALID_BUILD_TYPES[@]}"; do
                        valid_build_types_lower+=( "$(echo "$type" | tr '[:upper:]' '[:lower:]')" )
                    done
                    
                    if [[ ! " ${valid_build_types_lower[*]} " =~ " ${input_build_type} " ]]; then
                        echo "error: invalid build type: '${input_build_type}'"
                        exit 1
                    fi
                    # if [[ $input_build_type == "debug" ]]; then
                    #     input_build_type="Debug"
                    # elif [[ $input_build_type == "release" ]]; then
                    #     input_build_type="Release"
                    # fi

                    # BUILD_TYPE="${input_build_type}"
                    BUILD_TYPE="$2"

                    SHOULD_BUILD=true
                    shift 2  # 跳过 -b/--build <type>
                    break;
                    ;;
                3)  # -b/--build --target <target>
                    if [[ $2 != "--target" ]]; then
                        echo "Error: -b or --build parameter (-b | -b <build_type> | -b --target <target> | -b <build_type> --target <target>)"
                        exit 1
                    fi

                    # echo "target: $3"
                    BUILD_TARGET="$3"
                    SHOULD_BUILD=true
                    shift 3  # 跳过 -b/--build --target <target>
                    break;
                    ;;
                4)  # -b/--build <type> --target <target>
                    if [[ $3 != "--target" ]]; then
                        echo "Error: -b or --build parameter (-b | -b <build_type> | -b --target <target> | -b <build_type> --target <target>)"
                        exit 1
                    fi
                    
                    input_build_type=$(echo "$2" | tr '[:upper:]' '[:lower:]')
                    valid_build_types_lower=()
                    for type in "${VALID_BUILD_TYPES[@]}"; do
                        valid_build_types_lower+=( "$(echo "$type" | tr '[:upper:]' '[:lower:]')" )
                    done

                    if [[ ! " ${valid_build_types_lower[*]} " =~ " ${input_build_type} " ]]; then
                        echo "error: invalid build type: '${input_build_type}'"
                        exit 1
                    fi
                    # if [[ $input_build_type == "debug" ]]; then
                    #     input_build_type="Debug"
                    # elif [[ $input_build_type == "release" ]]; then
                    #     input_build_type="Release"
                    # fi

                    # BUILD_TYPE="${input_build_type}"
                    BUILD_TYPE="$2"

                    BUILD_TARGET="$4"
                    SHOULD_BUILD=true
                    shift 4  # 跳过 -b/--build <type> --target <target>
                    break;
                    ;;
                *)
                    echo "Error: Invalid number of arguments for -b/--build"
                    exit 1
                    ;;
            esac
            ;;

        -r|--run)
            if [[ $# -eq 1 ]]; then  # 检查参数总数为1（--run）
                SHOULD_RUN=true
                shift 1  # 跳过 --run
                break;
            elif [[ $# -ne 2 ]]; then  # 检查参数总数是否为2（--run + 构建类型）
                echo "Error: -r or --run parameter (-r | -r <build_type>)"
                exit 1
            fi
            
            input_build_type=$(echo "$2" | tr '[:upper:]' '[:lower:]')
            valid_build_types_lower=()
            for type in "${VALID_BUILD_TYPES[@]}"; do
                valid_build_types_lower+=( "$(echo "$type" | tr '[:upper:]' '[:lower:]')" )
            done

            if [[ ! " ${valid_build_types_lower[*]} " =~ " ${input_build_type} " ]]; then
                echo "error: invalid build type: '${input_build_type}'"
                exit 1
            fi
            # if [[ $input_build_type == "debug" ]]; then
            #     input_build_type="Debug"
            # elif [[ $input_build_type == "release" ]]; then
            #     input_build_type="Release"
            # fi

            # BUILD_TYPE="${input_build_type}"
            BUILD_TYPE="$2"

            SHOULD_RUN=true

            shift 2  # 跳过 --run 和构建类型
            # exit 0
            ;;

        -c|--clean)
            # echo "\$# = $#"
            if [[ $# -eq 1 ]]; then  # 检查参数总数是否为1（--clean）
                SHOULD_CLEAN=true
                shift 1  # 跳过 --clean
                break;
            elif [[ $# -ne 2 ]]; then
                echo "Error: -c or --clean parameter (-c | -c <build_type>)"
                exit 1
            fi
            
            input_build_type=$(echo "$2" | tr '[:upper:]' '[:lower:]')
            valid_build_types_lower=()
            for type in "${VALID_BUILD_TYPES[@]}"; do
                valid_build_types_lower+=( "$(echo "$type" | tr '[:upper:]' '[:lower:]')" )
            done

            if [[ ! " ${valid_build_types_lower[*]} " =~ " ${input_build_type} " ]]; then
                echo "error: invalid build type: '${input_build_type}'"
                exit 1
            fi
            # if [[ $input_build_type == "debug" ]]; then
            #     input_build_type="Debug"
            # elif [[ $input_build_type == "release" ]]; then
            #     input_build_type="Release"
            # fi

            # BUILD_TYPE="${input_build_type}"
            BUILD_TYPE="$2"

            SHOULD_CLEAN=true
            shift 2  # 跳过 --clean 和构建类型
            # exit 0
            ;;

        -h|--help)
            show_help
            shift 1  # 跳过 --help
            ;;

        *)
            echo "Unknown option: $1"
            exit 1
            ;;
    esac
done


# 
if [[ -z ${COMPILER_INFO} ]]; then
    BUILD_DIR="${SOURCE_DIR}/build/${BUILD_TYPE}"
elif [[ -z "${build_dir}" ]]; then
    BUILD_DIR="${SOURCE_DIR}/build/${COMPILER_INFO}-${BUILD_TYPE}"
elif [[ -n "${build_dir}" ]]; then
    BUILD_DIR="${build_dir}"
fi


# 配置项目
if [[ $SHOULD_CONFIGURE == true ]]; then
    echo "Compiler info : ${COMPILER_INFO}"
    echo "Build type    : ${BUILD_TYPE}"
    echo "Source dir    : ${SOURCE_DIR}"
    echo "Build dir     : ${BUILD_DIR}"
    echo "Generator     : ${GENERATOR}"
    echo "Parallel jobs : ${PARALLEL_JOBS}"
    echo "-------------------------------------------"

    # 检查 CMakeLists.txt 是否存在
    if [ ! -f "${SOURCE_DIR}/CMakeLists.txt" ]; then
        echo "Error: the Source directory Cannot find CMakeLists.txt"
        exit 1
    # else
    #     # echo "Found ${SOURCE_DIR}/CMakeLists.txt"
    fi

    if [ -f "${SOURCE_DIR}/conanfile.txt" ]; then
        conan install ${SOURCE_DIR} --output-folder=${BUILD_DIR} --build=missing --profile:host=${CONAN_HOST} --profile:build=${CONAN_BUILD}

        # 自动注释掉不兼容的行
        TOOLCHAIN_FILE="$BUILD_DIR/conan_toolchain.cmake"
        if [ -f "$TOOLCHAIN_FILE" ]; then
            echo "Patching $TOOLCHAIN_FILE ..."
            # 备份原文件
            cp "${TOOLCHAIN_FILE}" "${TOOLCHAIN_FILE}.bak"

            # 注释掉 set(CMAKE_GENERATOR_PLATFORM ...) / set(CMAKE_GENERATOR_TOOLSET ...) / message(STATUS "...TOOLSET...")
            # 以及 string(APPEND CONAN_CXX_FLAGS ...) / string(APPEND CONAN_C_FLAGS ...)
            sed -i.bak -E \
                's/^(set\(CMAKE_GENERATOR_(PLATFORM|TOOLSET).*FORCE\)|message\(STATUS "Conan toolchain: CMAKE_GENERATOR_TOOLSET=.*"\)|string\(APPEND CONAN_(CXX_FLAGS|C_FLAGS) " \/MP[0-9]+"\))/# \1/' \
                "$TOOLCHAIN_FILE"

            CMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake"
        fi
    fi

    if [[ $COMPILER_TYPE == "msvc" ]]; then
        # 通过 cmd 调用 MSVC 环境设置和构建命令
		cmd <<- EOD
			call "${MSVC_ENV_SCRIPT}" ${HOST_ARCH}
			cmake -S ${SOURCE_DIR} -B "${BUILD_DIR}" -G "${GENERATOR}" \
				-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" ${COMPILER_EXEC_P[@]} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}
		EOD
		cp ${BUILD_DIR}/compile_commands.json ${SOURCE_DIR}/build/compile_commands.json
		exit 0
    fi

    # 非 msvc 编译器
    { set -x; } 2>/dev/null
            cmake -S "${SOURCE_DIR}" -B "${BUILD_DIR}" -G "${GENERATOR}" \
                -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" ${COMPILER_EXEC_P[@]} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} || {
                    { set +x; } 2>/dev/null
                    echo "❌ CMake 配置失败，退出"; exit 1;
                }
    
    cp ${BUILD_DIR}/compile_commands.json ${SOURCE_DIR}/build/compile_commands.json

    { set +x; } 2>/dev/null
    exit 0
fi



# 构建项目
if [[ $SHOULD_BUILD == true ]]; then

    # 检查 CMakeLists.txt 是否存在
    if [ ! -f "${SOURCE_DIR}/CMakeLists.txt" ]; then
        echo "Error: the Source directory ${SOURCE_DIR} Cannot find CMakeLists.txt"
        exit 1
    # else
    #     # echo "Found ${SOURCE_DIR}/CMakeLists.txt"
    fi

    echo "Compiler info : ${COMPILER_INFO}"
    echo "Build type    : ${BUILD_TYPE}"
    echo "Source dir    : ${SOURCE_DIR}"
    echo "Build dir     : ${BUILD_DIR}"
    echo "Generator     : ${GENERATOR}"
    echo "Build target  : ${BUILD_TARGET}"
    echo "Parallel jobs : ${PARALLEL_JOBS}"
    echo "-------------------------------------------"

    Application_name=$(get_project_name_simple)
    Application="${BUILD_DIR}/bin/${Application_name}"

    if [ -f "${SOURCE_DIR}/conanfile.txt" ]; then
        conan install ${SOURCE_DIR} --output-folder=${BUILD_DIR} --build=missing --profile:host=${CONAN_HOST} --profile:build=${CONAN_BUILD}

        # 自动注释掉不兼容的行
        TOOLCHAIN_FILE="$BUILD_DIR/conan_toolchain.cmake"
        if [ -f "$TOOLCHAIN_FILE" ]; then
            echo "Patching $TOOLCHAIN_FILE ..."
            # 备份原文件
            cp "${TOOLCHAIN_FILE}" "${TOOLCHAIN_FILE}.bak"

            # 注释掉 set(CMAKE_GENERATOR_PLATFORM ...) / set(CMAKE_GENERATOR_TOOLSET ...) / message(STATUS "...TOOLSET...")
            # 以及 string(APPEND CONAN_CXX_FLAGS ...) / string(APPEND CONAN_C_FLAGS ...)
            sed -i.bak -E \
                's/^(set\(CMAKE_GENERATOR_(PLATFORM|TOOLSET).*FORCE\)|message\(STATUS "Conan toolchain: CMAKE_GENERATOR_TOOLSET=.*"\)|string\(APPEND CONAN_(CXX_FLAGS|C_FLAGS) " \/MP[0-9]+"\))/# \1/' \
                "$TOOLCHAIN_FILE"

            CMAKE_TOOLCHAIN_FILE="conan_toolchain.cmake"
        fi
    fi

    if [[ $COMPILER_TYPE == "msvc" ]]; then
        # 通过 cmd 调用 msvc 环境设置和构建命令
		cmd <<- EOD
			call "${MSVC_ENV_SCRIPT}" ${HOST_ARCH}
			cmake -S ${SOURCE_DIR} -B "${BUILD_DIR}" -G "${GENERATOR}" \
				-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" ${COMPILER_EXEC_P[@]} -DCMAKE_TOOLCHAIN_FILE="${CMAKE_TOOLCHAIN_FILE}"
			cp ${BUILD_DIR}/compile_commands.json ${SOURCE_DIR}/build/compile_commands.json
			cmake --build "${BUILD_DIR}" --target "${BUILD_TARGET}" -j${PARALLEL_JOBS}
		EOD
        echo ""
        echo "-------------------------------------------"
        echo "Application: ${Application}"
        exit 0
    fi

    # 非 msvc 编译器
    { set -x; } 2>/dev/null
            cmake -S "${SOURCE_DIR}" -B "${BUILD_DIR}" -G "${GENERATOR}" \
                -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" ${COMPILER_EXEC_P[@]} -DCMAKE_TOOLCHAIN_FILE="${CMAKE_TOOLCHAIN_FILE}" || {
                { set +x; } 2>/dev/null
                echo "❌ CMake 配置失败，退出"; exit 1;
            }
    { set +x; } 2>/dev/null

    cp ${BUILD_DIR}/compile_commands.json ${SOURCE_DIR}/build/compile_commands.json

    { set -x; } 2>/dev/null
    cmake   --build "${BUILD_DIR}" --target "${BUILD_TARGET}" -j${PARALLEL_JOBS} || {
                { set +x; } 2>/dev/null
                echo "❌ CMake 构建失败，退出"; exit 1;
            }
    { set +x; } 2>/dev/null
    echo "-------------------------------------------"
    echo "Application: ${Application}"
    exit 0
fi


# 运行可执行文件
if [[ $SHOULD_RUN == true ]]; then
    Application_name=$(get_project_name_simple)
    Application="${BUILD_DIR}/bin/${Application_name}"

    # 检查可执行文件是否存在
    if [ ! -f "${Application}" ]; then
        echo "Error: the executable file Cannot find ${BUILD_DIR}/bin/${Application_name}"
        exit 1
    # else
    #     echo "Found ${BUILD_DIR}/bin/${Application_name}"
    fi

    echo "Running ${Application}"
    echo "-------------------------------------------"

    if [ ! "${COMPILER_TYPE}" = "msvc" ] && [ "$OSTYPE" = "msys" ]; then
        # cygwin 环境下运行可执行文件
        # powershell.exe -Command "& {Start-Process -FilePath '${Application}' -Wait -Verb RunAs}"
        powershell.exe -Command "${Application}"
        exit 0
    fi

    ${Application}

    exit 0
fi


# 清理构建目录
if [[ $SHOULD_CLEAN == true ]]; then
    echo "rm -rf ${BUILD_DIR} ${SOURCE_DIR}/build/compile_commands.json"
    rm -rf "${BUILD_DIR}" ${SOURCE_DIR}/build/compile_commands.json
    exit 0
fi


# 显示帮助信息
# show_help
